﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Web;
using System.Data;
using Microsoft.SharePoint;
using System.Web.UI.WebControls;

namespace TemplateLibraryConnector.Data
{
    public class TemplateLibraryUtility
    {

        
        private static string GetUrl(string fullUrl, int segmentsSkipped)
        {
            var fullUri = new Uri(fullUrl);
            
            if( fullUrl.Contains("RootFolder"))
            {
                var rootFolder = HttpUtility.ParseQueryString(fullUri.Query).Get("RootFolder");
                return fullUri.GetLeftPart(UriPartial.Authority) + rootFolder + "/";
            }
            
            if (!fullUrl.EndsWith(@"/"))
            {
                //Add additional segment to remove file and Forms\
                segmentsSkipped += 2;
                
            }
            var urlBuilder = new StringBuilder();
            urlBuilder.Append(fullUri.GetComponents(UriComponents.SchemeAndServer, UriFormat.Unescaped));
            for (int i = 0; i < fullUri.Segments.Length - segmentsSkipped; i++)
            {
                urlBuilder.Append(fullUri.Segments[i]);
            }
            return urlBuilder.ToString();
        }

        /// <remarks>
        /// Assume url follow following pattern: http://server/sites/sitename/LibraryName/Forms/AllItems.aspx?whatever
        /// Returns url WITH library, without crap.
        /// </remarks>
        internal static string GetLibraryUrl(string fullUrl)
        {
            return GetUrl(fullUrl, 0);
        }


        /// <remarks>
        /// Assume url follow following pattern: http://server/sites/sitename/LibraryName/Forms/AllItems.aspx?whatever
        /// Returns url without library
        /// </remarks>
        internal static string GetSiteUrlFromLibrary(string fullUrl)
        {
            return GetUrl(fullUrl, 1);
        }

        /// <remarks>
        /// Assume url follow following pattern: http://server/sites/sitename/LibraryName/
        /// In order to avoid dispose problems, must open the site, web and library in one method
        /// Use these 2 functions to do that
        /// </remarks>
        internal static SPSite GetDocumentLibrarySite(string doclibAbsoluteUrl)
        {
            string libraryWeb = GetSiteUrlFromLibrary(doclibAbsoluteUrl);
            var site = new SPSite(libraryWeb);
            return site;
        }

        /// <remarks>
        /// Assume url follow following pattern: http://server/sites/sitename/LibraryName/
        /// In order to avoid dispose problems, must open the site, web and library in one method
        /// Use these 2 functions to do that
        /// </remarks>
        internal static SPWeb GetDocumentLibraryWeb(string doclibAbsoluteUrl, SPSite site)
        {
            string libraryWeb = GetSiteUrlFromLibrary(doclibAbsoluteUrl);
            
            var relativeSubWebUrl = libraryWeb.Replace(site.Url, "");
            SPWeb web = null;
            if (relativeSubWebUrl == @"/")
            {
                web = site.RootWeb;
            }
            else
            {
                if (relativeSubWebUrl.StartsWith(@"/"))
                    relativeSubWebUrl = relativeSubWebUrl.TrimStart('/');
                web = site.OpenWeb(relativeSubWebUrl);
            }

            return web;
        }

        internal static SPWeb GetDocumentLibraryWebFromUrl(string siteUrl, SPSite site)
        {
            var relativeSubWebUrl = siteUrl.Replace(site.Url, "");
            SPWeb web = null;
            if (relativeSubWebUrl == @"/")
            {
                web = site.RootWeb;
            }
            else
            {
                if (relativeSubWebUrl.StartsWith(@"/"))
                    relativeSubWebUrl = relativeSubWebUrl.TrimStart('/');
                web = site.OpenWeb(relativeSubWebUrl);
            }

            return web;
        }


        public static List<SPField> TemplateFields(Utility.TemplateLibraryConnectorSettings settings, Guid guidView, bool addRequiredFields)
        {
            var templateHubAddress = settings.GetTemplateHubAddress(string.Empty);

            using (var site = TemplateLibraryUtility.GetDocumentLibrarySite(templateHubAddress))
            {
                using (var web = TemplateLibraryUtility.GetDocumentLibraryWebFromUrl(templateHubAddress, site))
                {
                    var listId = new Guid(settings.TemplateListIds);
                    var templateLibrary = web.Lists[listId] as SPDocumentLibrary;

                    if (templateLibrary != null)
                    {
                        var view = guidView == Guid.Empty ? templateLibrary.DefaultView : templateLibrary.Views[guidView];

                        var viewFields = view.ViewFields;

                        if (addRequiredFields)
                        {
                            AddRequiredFieldsToView(viewFields, templateLibrary.Fields);
                        }

                        return (from string viewField in viewFields where templateLibrary.Fields.ContainsField(viewField) select templateLibrary.Fields.GetField(viewField)).ToList();
                    }
                    return null;
                }
            }
        }


        public static void AddRequiredFieldsToView(SPViewFieldCollection viewFields, SPFieldCollection fields)
        {
            if (!viewFields.Exists("FileLeafRef"))
                    viewFields.Add(fields.GetFieldByInternalName("FileLeafRef"));

            if (!viewFields.Exists("FileDirRef"))
                viewFields.Add(fields.GetFieldByInternalName("FileDirRef"));

            if (!viewFields.Exists("EncodedAbsUrl"))
                viewFields.Add(fields.GetFieldByInternalName("EncodedAbsUrl"));

            if (!viewFields.Exists("FileRef"))
                viewFields.Add(fields.GetFieldByInternalName("FileRef"));
                
            if (!viewFields.Exists("Title"))
                viewFields.Add(fields.GetFieldByInternalName("Title"));

            if (!viewFields.Exists("Template_x0020_title") && fields.TryGetFieldByStaticName("Template_x0020_title") != null)
                viewFields.Add(fields.GetFieldByInternalName("Template_x0020_title"));

            if (!viewFields.Exists("ID"))
                viewFields.Add(fields.GetFieldByInternalName("ID"));
        }


        internal static DataTable ToDataTable(List<SPListItem> list)
        {
            var dataTable = new DataTable();

            foreach (var item in list)
            {
                if (item.HasPublishedVersion)
                {

                    var dtRow = dataTable.NewRow();
                    foreach (SPField field in item.Fields.Cast<SPField>().Where(field => !field.Hidden))
                    {
                        if (!dataTable.Columns.Contains(field.StaticName))
                        {
                            dataTable.Columns.Add(field.StaticName);
                        }
                        //fields not always available - have not found a better method than catching errors
                        try
                        {
                            if (item.Fields.TryGetFieldByStaticName(field.StaticName) != null)
                            {
                                dtRow[field.StaticName] = field.GetFieldValueAsText(item[field.Id]);
                            }
                        }
                        catch
                        {
                        }
                    }
                    dataTable.Rows.Add(dtRow);
                }
            }

            return dataTable;

        }

        internal static DataTable PerformFilter(DataTable items, string strSearch)
        {
            if (!String.IsNullOrEmpty(strSearch))
            {
                var srcTerms = strSearch.ToLowerInvariant().TrimStart(' ').TrimEnd(' ').Split(' ').ToList();
                var filtereditems = new List<DataRow>();
                // Find all files that matches all of the words in the search box.
                filtereditems.AddRange(
                    from DataRow d in items.Rows 
                    from DataColumn c in items.Columns 
                    where srcTerms.All(s => d[c].ToString().ToLowerInvariant().Contains(s)) //Change to .Any to get matches on any of the search terms
                    select d);
                return filtereditems.Count > 0 ? filtereditems.CopyToDataTable<DataRow>() : items.Clone();
            }
            else
            {
                return items;
            }
        }

        internal static DataTable SortList(DataTable items, string sortExpression)
        {
            return !String.IsNullOrEmpty(sortExpression) ? items.Select("", sortExpression).CopyToDataTable<DataRow>() : items;
        }
    }
}
